package com.org.core.datasource;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.org.core.container.CommonContainer;
import com.org.core.utils.PropertyUtil;

/**
 * dbcp 数据源服务－ mysql
 *
 */
public class DbcpMysqlDataSource {
	private static Log log = LogFactory.getLog(DbcpMysqlDataSource.class);
	// 是否配置了读写分离
	private boolean useBak = false;
	
	public void init(){
		Properties pro = new Properties();
		try {
			String fileName = "/WEB-INF/config/mysql_db.properties";
			InputStream in = CommonContainer.getServletContext().getResourceAsStream(fileName);
			pro.load(in);
		} catch (IOException e1) {
			log.info("MysqlDataSource 加载数据源配置文件失败...");
			e1.printStackTrace();
			return;
		}
		
		String driverClassName = pro.getProperty("driverClassName");
		String url = pro.getProperty("url");
		String username = pro.getProperty("username");
		String password = pro.getProperty("password");
		String maxActive = pro.getProperty("maxActive");
		String initialSize = pro.getProperty("initialSize");
		String maxIdle = pro.getProperty("maxIdle");
		String minIdle = pro.getProperty("minIdle");
		String maxWait = pro.getProperty("maxIdle");
		String defaultAutoCommit = pro.getProperty("defaultAutoCommit");
		
		BasicDataSource temp = new BasicDataSource();
		
		temp.setDriverClassName(driverClassName);
		temp.setUrl(url);
		temp.setUsername(username);
		temp.setPassword(password);
		// <!-- 是否对已备语句进行池管理（布尔值），是否对PreparedStatement进行缓存 -->
		// <property name="poolPreparedStatements" value="true" />
		// <!-- 连接初始值，连接池启动时创建的连接数量的初始值 -->
		temp.setInitialSize(Integer.valueOf(initialSize));
		// <!-- 连接池的最大值，同一时间可以从池分配的最多连接数量，0时无限制 -->
		temp.setMaxActive(Integer.valueOf(maxActive));
		// <!-- 最大空闲值.当经过一个高峰时间后，连接池可以慢慢将已经用不到的连接慢慢释放一部分，一直减少到maxIdle为止 ，0时无限制-->
		temp.setMaxIdle(Integer.valueOf(maxIdle));
		// <!-- 最小空闲值.当空闲的连接数少于阀值时，连接池就会预申请去一些连接，以免洪峰来时来不及申请 -->
		temp.setMinIdle(Integer.valueOf(minIdle));
		// 最大等待时间，当没有可用连接时，连接池等待连接释放的最大时间，超过该时间限制会抛出异常，如果设置-1表示无限等待（默认为无限，调整为60000ms，避免因线程池不够用，而导致请求被无限制挂起） 
		temp.setMaxWait(Integer.valueOf(maxWait));
		// <!-- 是否对sql进行自动提交 -->
		temp.setDefaultAutoCommit(Boolean.valueOf(defaultAutoCommit));
		
		template = temp;

		String backupConfig = pro.getProperty("backupConfig");
		if(StringUtils.isNotBlank(backupConfig)) {
			// 如果存在备库的配置文件
			String[] backupConfigArr = backupConfig.split(",");
			for (int i = 0; i < backupConfigArr.length; i++) {
				initBackupDatasource(StringUtils.trim(backupConfigArr[i]), "template$"+i);
			}
			this.useBak  = true;
		}
	}
	

	/**
	 * 初始化备库数据源
	 * @param fileName  文件名
	 * @param dataSourceName 数据源的beanId
	 */
	public void initBackupDatasource(String fileName, String dataSourceName){
		Properties pro = PropertyUtil.getProperties(fileName);
		String driverClassName = pro.getProperty("driverClassName");
		String url = pro.getProperty("url");
		String username = pro.getProperty("username");
		String password = pro.getProperty("password");
		String maxActive = pro.getProperty("maxActive");
		String initialSize = pro.getProperty("initialSize");
		String maxIdle = pro.getProperty("maxIdle");
		String minIdle = pro.getProperty("minIdle");
		String maxWait = pro.getProperty("maxIdle");
		String defaultAutoCommit = pro.getProperty("defaultAutoCommit");
		
		BasicDataSource temp = new BasicDataSource();
		
		temp.setDriverClassName(driverClassName);
		temp.setUrl(url);
		temp.setUsername(username);
		temp.setPassword(password);
		// <!-- 是否对已备语句进行池管理（布尔值），是否对PreparedStatement进行缓存 -->
		// <property name="poolPreparedStatements" value="true" />
		// <!-- 连接初始值，连接池启动时创建的连接数量的初始值 -->
		temp.setInitialSize(Integer.valueOf(initialSize));
		// <!-- 连接池的最大值，同一时间可以从池分配的最多连接数量，0时无限制 -->
		temp.setMaxActive(Integer.valueOf(maxActive));
		// <!-- 最大空闲值.当经过一个高峰时间后，连接池可以慢慢将已经用不到的连接慢慢释放一部分，一直减少到maxIdle为止 ，0时无限制-->
		temp.setMaxIdle(Integer.valueOf(maxIdle));
		// <!-- 最小空闲值.当空闲的连接数少于阀值时，连接池就会预申请去一些连接，以免洪峰来时来不及申请 -->
		temp.setMinIdle(Integer.valueOf(minIdle));
		// 最大等待时间，当没有可用连接时，连接池等待连接释放的最大时间，超过该时间限制会抛出异常，如果设置-1表示无限等待（默认为无限，调整为60000ms，避免因线程池不够用，而导致请求被无限制挂起） 
		temp.setMaxWait(Integer.valueOf(maxWait));
		// <!-- 是否对sql进行自动提交 -->
		temp.setDefaultAutoCommit(Boolean.valueOf(defaultAutoCommit));
		
		templateBak.add(temp);
	}
	
	public static DbcpMysqlDataSource getInstance(){
		if(hds == null) {
			hds = new DbcpMysqlDataSource();
		}
		return hds;
	}
	
	public void destroy(){
		if(template != null) {
			try {
				template.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(templateBak != null) {
			if(templateBak.size() > 0) {
				for (int i = 0; i < templateBak.size(); i++) {
					try {
						templateBak.get(i).close();
					} catch (SQLException e) {
						e.printStackTrace();
					}
				}
			}
		}
		hds = null;
	}
	
	public Connection getConnection(){
		Connection con = null;
		try {
			con = template.getConnection();
		} catch (SQLException e) {
			log.info("获取数据库连接异常：" + e.getMessage());
		}
		return con;
	}
	
	public Connection getConnectionBak(){
		if(useBak) {
			// 如果使用了读写分离，存在备库的配置
			try {
				return getDefaultBakDataSource().getConnection();
			} catch (SQLException e) {
				log.info("获取备用数据库连接异常：" + e.getMessage());
			}
			return null;
		}
		// 如果没有， 则使用主库
		return getConnection();
	}
	
	private BasicDataSource getDefaultBakDataSource() {
		if(templateBak != null && templateBak.size() >0) {
			return templateBak.get(0);
		}
		return null;
	}
	
	private static DbcpMysqlDataSource hds = null;

	private BasicDataSource template;
	private List<BasicDataSource> templateBak = new ArrayList<BasicDataSource>();
	//private Log log = LogFactory.getLog(HikaricpMysqlDataSourceService.class);
}
